<?php

namespace common\models\user;

use common\components\wechat\MpWechat;
use common\components\wechat\WechatOpen;
use common\models\BaseUser;
use Yii;
use common\helpers\ArrayHelper;
use yii\db\Exception;
use yii\helpers\Inflector;
use yii\web\Request;

/**
 * This is the model class for table "{{%user_connect}}".
 *
 * @property int $id
 * @property string $client 客户端
 * @property string $user_id 用户ID
 * @property string $openid 第三方帐号OPENID
 * @property string $unionid 第三方帐号UNIONID
 * @property string $created_at 创建时间
 * @property mixed $refreshToken
 * @property BaseUser $user
 * @property mixed $accessToken
 * @property mixed $cacheToken
 * @property mixed $meta
 * @property string $updated_at 更新时间
 */
class UserConnect extends \common\db\ActiveRecord {

    use \common\traits\relation\UserData;

    const CLIENT_WECHAT_OPEN = 'wechat_open';
    const CLIENT_WECHAT_ACCOUNT = 'wechat_account';
    const CLIENT_WECHAT_MP = 'wechat_mp';
    const CLIENT_MP = 'wechat_mp';
    const CLIENT_WEIBO = 'weibo';
    const CLIENT_QQ = 'qq';

    /**
     * {@inheritdoc}
     */
    public static function tableName() {
        return '{{%user_connect}}';
    }

    /**
     * {@inheritdoc}
     */
    public function rules() {
        return [
            [['user_id', 'created_at', 'updated_at'], 'integer'],
            [['client'], 'string', 'max' => 32],
            [['openid', 'unionid'], 'string', 'max' => 255],
            [['client', 'user_id'], 'unique', 'targetAttribute' => ['client', 'user_id']],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function attributeLabels() {
        return [
            'id' => 'ID',
            'client' => '客户端',
            'user_id' => '用户ID',
            'openid' => '第三方帐号OPENID',
            'unionid' => '第三方帐号unionid',
            'created_at' => '创建时间',
            'updated_at' => '更新时间',
        ];
    }

    public function getUser() {
        return $this->hasOne(Yii::$app->user->identityClass, ['id' => 'user_id']);
    }

    public function getMeta() {
        return $this->hasOne(UserMeta::class, ['id' => 'user_id']);
    }

    public function getCacheToken() {
        return Yii::$app->cache->get('client_' . $this->id);
    }

    public function setCacheToken($data) {
        Yii::$app->cache->set('client_' . $this->id, $data, 30 * 86400);
    }

    public function setAccessToken($data, $expired) {
        Yii::$app->cache->set('client_access_token' . $this->id, $data, $expired);
    }

    public function getAccessToken() {
        return Yii::$app->cache->set('client_access_token' . $this->id);
    }

    public function setRefreshToken($data) {
        Yii::$app->cache->set('client_refresh_token' . $this->id, $data, 28 * 86400);
    }

    public function getRefreshToken() {
        return Yii::$app->cache->set('client_refresh_token' . $this->id);
    }

    public function getAuthData($format = true) {
        $clientMethod = 'authClient' . Inflector::camelize($this->client);
        if (!method_exists($this, $clientMethod)) {
            return null;
        }
        $cacheData = $this->getCacheToken();
        if ($cacheData === false) {
            return null;
        }
        try {
            $userinfo = $this->$clientMethod($cacheData);
        } catch (Exception $exc) {
            Yii::error($exc->getTraceAsString());
            return null;
        }
        if ($userinfo === false) {
            return null;
        }
        if ($format) {
            $avatar = ArrayHelper::getValue($userinfo, 'avatar');
            $location = ArrayHelper::getValue($userinfo, 'location');
            $nickname = ArrayHelper::getValue($userinfo, 'nickname');
            $gender = ArrayHelper::getValue($userinfo, 'gender', 0);
            return compact('avatar', 'location', 'nickname', 'gender');
        }
        return $userinfo;
    }

    public function canBindUser() {
        return $this->user_id && $this->user && $this->user->mobile;
    }

    /**
     * 自动注册
     *
     * @return bool|BaseUser
     * @throws \yii\base\Exception
     */
    public function autoRegister() {
        if ($this->user_id) {
            return $this->user;
        }
        $userinfo = $this->getAuthData(false);
        if (!$userinfo) {
            return false;
        }
        $avatar = ArrayHelper::remove($userinfo, 'avatar');
        $location = ArrayHelper::remove($userinfo, 'location');
        $nickname = ArrayHelper::remove($userinfo, 'nickname');
        $gender = (int) ArrayHelper::remove($userinfo, 'gender', 0);
        /* @var $user BaseUser */
        $user = new Yii::$app->user->identityClass;
        $user->generateAuthKey();
        $user->setAvatar($avatar);
        $user->setUniqueNickname($nickname);
        $user->setUsernameByOpenid($this->client, $this->openid);
        if (Yii::$app->request instanceof Request) {
            $user->ip = Yii::$app->request->userIP;
        }
        //
        $meta = new UserMeta();
        $meta->location = $location;
        $meta->gender = $gender;
        $transaction = Yii::$app->db->beginTransaction();
        try {
            if (!$user->save()) {
                throw new Exception('账号信息创建失败');
            }
            $meta->id = $user->id;
            if (!$meta->save()) {
                throw new Exception('用户基本信息保存失败:' . $meta->errorMsg);
            }
            $this->user_id = $user->id;
            if (!$this->save()) {
                throw new Exception('用户基本信息保存失败');
            }
            $transaction->commit();
        } catch (Exception $e) {
            $transaction->rollBack();
            Yii::error($e->getMessage());
            return false;
        }
        return $user;
    }

    /**
     * @param $data
     * @return array|bool
     */
    protected function authClientWechatAccount($data) {
        $openid = ArrayHelper::getValue($data, 'openid');
        $accessToken = ArrayHelper::getValue($data, 'access_token');
        if (!$openid || !$accessToken) {
            return false;
        }
        if (YII_ENV_DEV) {
            return [
                'nickname' => '张三',
                'gender' => 1,
                'avatar' => '/assets/avatar/default.png',
                'location' => '中国北京',
            ];
        }
        /* @var $wechat MpWechat */
        $wechat = Yii::$app->wechat;
        $userinfo = $wechat->getSnsUserInfo($openid, $accessToken);
        if ($userinfo === false) {
            $refresh_token = ArrayHelper::getValue($data, 'refresh_token');
            $refreshData = $wechat->refreshOauth2AccessToken($refresh_token);
            $accessToken = ArrayHelper::getValue($refreshData, 'access_token');
            $userinfo = $wechat->getSnsUserInfo($openid, $accessToken);
        }
        if ($userinfo === false) {
            return false;
        }
        $avatar = ArrayHelper::getValue($userinfo, 'headimgurl');
        $location = ArrayHelper::getValue($userinfo, 'country') . ArrayHelper::getValue($userinfo, 'province') . ArrayHelper::getValue($userinfo, 'city');
        $gender = ArrayHelper::getValue($userinfo, 'sex');
        $nickname = ArrayHelper::getValue($userinfo, 'nickname');
        return compact('nickname', 'gender', 'avatar', 'location');
    }

    /**
     * @param $data
     * @return array|bool
     */
    protected function authClientWechatOpen($data) {
        $openid = ArrayHelper::getValue($data, 'openid');
        $accessToken = ArrayHelper::getValue($data, 'access_token');
        if (!$openid || !$accessToken) {
            return false;
        }
        /* @var $wechat WechatOpen */
        $wechat = Yii::$app->openWechat;
        $userinfo = $wechat->getSnsUserInfo($openid, $accessToken);
        if ($userinfo === false) {
            $refresh_token = ArrayHelper::getValue($data, 'refresh_token');
            $refreshData = $wechat->refreshOauth2AccessToken($refresh_token);
            $accessToken = ArrayHelper::getValue($refreshData, 'access_token');
            $userinfo = $wechat->getSnsUserInfo($openid, $accessToken);
        }
        if ($userinfo === false) {
            return false;
        }
        $avatar = ArrayHelper::getValue($userinfo, 'headimgurl');
        $location = ArrayHelper::getValue($userinfo, 'country') . ArrayHelper::getValue($userinfo, 'province') . ArrayHelper::getValue($userinfo, 'city');
        $gender = ArrayHelper::getValue($userinfo, 'sex');
        $nickname = ArrayHelper::getValue($userinfo, 'nickname');
        return compact('nickname', 'gender', 'avatar', 'location');
    }

}
